#ifndef FACILITY_H
#define FACILITY_H
/// @brief 实现有关设施的操作

#ifndef HEAD_H
#include "../head.h"
#endif

#ifndef CARGO_H
#include "../Cargo/Cargo.h"
#endif

#ifndef GATE_H
#include "../Grid/Gate.h"
#endif

#ifndef FACILITY_DEFINE_H
#include "Facility_Define.h"
#endif

#ifndef CARGO_MANAGER_H
#include "../Cargo/Cargo_Manager.h"
#endif

#ifndef OBJECTQT_H
#include "../utils/Object_qt.h"
#endif

/**************************************
 * @brief 设施的实例化类
 *
 **************************************/
class Facility
{
protected:
    // inline static std::pair<double,double>generateCargoPos(){

    // }
    FacilityDefine *define;                                             // 设备的定义
    Cargo_Manager * cargo_manager;                                      // 货物管理器
    Object_Qt *object_qt;                                               // 图片
    int time_record;                                                    // 计时器
    Coordinate coordinate;                                              // 图片左上角坐标
    double my_x , my_y ;
    FacilityDirection facility_direction;                               // 方向
    int width, height;                                              // 宽度 和 高度
    std::vector<EnterGate> abs_enters;                          // 入口 绝对位置
    std::vector<ExitGate> abs_exits;                            // 出口绝对位置
    std::vector<std::pair<Facility*,int>> next_facility, pre_facility;  // 出入设备 first是设备，second是设备对应的几号出入口
    std::vector<Cargo *> incargos, storecargos, outcargos;                           // 出入货物
public:
    Facility(FacilityDefine *define, FacilityDirection f_dir, Coordinate coordinate, Cargo_Manager * cargo_manager);

    // 连接 和 断连 Object_Qt 注意断连不释放内存
    void linkObject(Object_Qt * obj = null);
    Object_Qt * removeObject();

    /// @brief 处理in的货物
    /// sendCargo
    /// 如果堵塞或没有材料直接返回
    /// 否则计时器++，during_process(), belt需要在这里 移动in货物
    /// 如果 time > define.interval time = 0,则调用finishProcess函数
    virtual void processCargo();

    /// @brief 纯虚函数
    /// 1. 根据具体的type对cargo进行加工
    ///     对于各类情况的处理
    ///     如类型错误等等，也就是说，如果有错误的输入，设备将停止工作
    /// 2. 把得到的新cargo放入outcargos中
    /// 3. sendcargo();
    virtual void finishProcess();
    /// @brief 判断是否是合法可以处理的，默认为true;
    virtual bool isValid();
    /// @brief 这个函数应该是除了传送带会修改，
    /// 其他不做任何事
    virtual void duringProcess();

    /// @brief 尝试从后方拾取货物, 假定不耗时
    /// 对于每个in，如果没有满，则尝试 pre.out->this.in
    virtual void takeCargo();

    /// @brief 尝试向前方传送货物, 假定不耗时
    /// 对于每个out，如果满了，则尝试 this.out->next.in
    virtual void sendCargo();

    /// @brief 存在一个in为空则为真
    virtual bool inEmpty();
    /// @brief 所有out为空则为真
    virtual bool outEmpty();

    /// @brief 得到hash_id
    virtual inline std::string getHashId(){
        if(!define) return "";
        return define->get_Hashid();
    }
    /// @brief 得到f_type
    virtual inline FacilityType getFacilityType(){
        if(!define) return FacilityType::Facility_NONE;
        return define->facility_type;
    }

    virtual ~Facility();
    friend class GameLogic;
    friend class Facility_Manager;
};

#endif
